<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
    <title>Document</title>
</head>
<body>
<div id="virtual-dom">
<!--    模拟 DOM 树-->
    <p>Virtual DOM</p>
    <ul id="list">
        <li class="item">Item 1</li>
        <li class="item">Item 2</li>
        <li class="item">Item 3</li>
    </ul>
    <div>Hello World</div>
</div>

<script>
    /**
     * Element virdual-dom 对象定义
     * @param {String} tagName - dom 元素名称
     * @param {Object} props - dom 属性
     * @param {Array<Element|String>} - 子节点
     */
    // 用 JavaScript 对象来表示 DOM 节点，使用对象的属性记录节点的类型、属性、子节点等
    function Element(tagName, props, children) {
        this.tagName = tagName;
        this.props = props;
        this.children = children;
        // dom 元素的 key 值，用作唯一标识符
        if (props.key) {
            this.key = props.key
        }
    }

    function el(tagName, props, children) {
        return new Element(tagName, props, children);
    }
    // 构建虚拟的 DOM
    let ul = el('div', { id: 'Virtual DOM' }, [
        el('p', {}, ['Virtual DOM']),
        el('ul', { id: 'list' }, [
            el('li', { class: 'item' }, ['Item 1']),
            el('li', { class: 'item' }, ['Item 2']),
            el('li', { class: 'item' }, ['Item 3'])
        ]),
        el('div', {}, ['Hello,World'])
    ])

    /**
     * render 将virdual-dom 对象渲染为实际 DOM 元素
     */
    // 虚拟 DOM 转换成真实 DOM
    //  render 方法，会根据 tagName 构建一个真正的 DOM 节点，然后设置这个节点的属性，最后递归地把自己的子节点也构建起来。
    Element.prototype.render = function () {
        // 创建节点
        let el = document.createElement(this.tagName);

        let props = this.props;
        // 设置节点的 DOM 属性
        for (let propName in props) {
            let propValue = props[propName];
            el.setAttribute(propName, propValue)
        }

        let children = this.children || []
        for (let child of children) {
            let childEl = (child instanceof Element)
                ? child.render() // 如果子节点也是虚拟 DOM, 递归构建 DOM 节点
                : document.createTextNode(child) // 如果是文本，就构建文本节点

            el.appendChild(childEl);
        }

        return el;
    }

    let ulRoot = ul.render();
    // 构建好的 DOM 结构添加到页面 body 上
    document.body.appendChild(ulRoot);
    console.log(ul);
</script>
</body>

</html>


